package com.sumauto.view;

import android.annotation.SuppressLint;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;

import com.sumauto.R;

import java.util.ArrayList;

/**
 * Created by Lincoln on 16/3/22.
 * 超级布局
 */
@SuppressWarnings("unused")
public class SupperLayout extends ViewGroup {
    public static final int AUTO = -1;

    /*宽被划分为多少个单元*/
    private int mWidthUnits;

    /*高被划分为多少个单元*/
    private int mHeightUnits;

    /*1个单位 的大小*/
    private double mUnitSize;

    /*是否自定决定高度*/
    private boolean mAutoDetermineHeight;
    /*是否自定决定宽度*/
    private boolean mAutoDetermineWidth;
    private int mDependOn;
    OnDrawListener mOnDrawListener;
    /**/
    ArrayList<View> unMeasureChildren = new ArrayList<>();

    private boolean editMode;


    public enum BaseType {
        START, CENTER, END, CENTER_ALIGN
    }

    public SupperLayout(Context context) {
        this(context, null);
    }

    public SupperLayout(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public SupperLayout(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);

        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.SupperLayout);
        mWidthUnits = a.getInt(R.styleable.SupperLayout_layout_width_units, AUTO);

        mHeightUnits = a.getInt(R.styleable.SupperLayout_layout_height_units, AUTO);

        editMode=a.getBoolean(R.styleable.SupperLayout_editMode,false);

        mDependOn = a.getInt(R.styleable.SupperLayout_dependOn, 0);
        a.recycle();
        setWillNotDraw(false);
        if (mWidthUnits == AUTO && mHeightUnits == AUTO) {
            mWidthUnits = 360;
        }
        mAutoDetermineHeight = (mHeightUnits == AUTO);
        mAutoDetermineWidth = (mWidthUnits == AUTO);
    }

    void measureDependOnWidth(int widthMeasureSpec, int heightMeasureSpec) {
        int width = MeasureSpec.getSize(widthMeasureSpec);

        if (width == 0) {
            width = getResources().getDisplayMetrics().widthPixels;
        }
        int contentWidth = width - getPaddingLeft() - getPaddingRight();

        mUnitSize = contentWidth / (double) mWidthUnits;

        int heightMode = MeasureSpec.getMode(heightMeasureSpec);
        int height = MeasureSpec.getSize(heightMeasureSpec);
        boolean canAutoDetermine = true;
        if (heightMode == MeasureSpec.EXACTLY) {
            this.mHeightUnits = (int) (height / mUnitSize);
            canAutoDetermine = false;
        }

        unMeasureChildren.clear();
        int maxHeight = 0;
        for (int i = 0, N = getChildCount(); i < N; i++) {
            View child = getChildAt(i);
            LayoutParams layoutParams = (LayoutParams) child.getLayoutParams();
            if (layoutParams.height == LayoutParams.MATCH_PARENT && this.mHeightUnits <= 0 && canAutoDetermine) {
                //最大高度还没有计算出来，所以先不计算child的高度
                unMeasureChildren.add(child);
                continue;
            }

            measureChild(child);
            if (child.getVisibility() != GONE) {
                maxHeight = Math.max(unitToSize(layoutParams.y) + child.getMeasuredHeight(), maxHeight);
            }
        }

        if (canAutoDetermine) {
            if (mAutoDetermineHeight) {
                this.mHeightUnits = sizeToUnit(maxHeight);
            }
            height = (int) (this.mHeightUnits * mUnitSize + getPaddingTop() + getPaddingBottom());
        }

        //计算child 为match_parent的高度
        for (int i = 0, N = unMeasureChildren.size(); i < N; i++) {
            measureChild(unMeasureChildren.get(i));
        }
        unMeasureChildren.clear();

        setMeasuredDimension(width, height);
    }

    void measureDependOnHeight(int widthMeasureSpec, int heightMeasureSpec) {
        int height = MeasureSpec.getSize(heightMeasureSpec);
        if (height == 0) {
            //保证height不为0
            height = getResources().getDisplayMetrics().heightPixels;
        }

        int contentHeight = height - getPaddingTop() - getPaddingBottom();

        mUnitSize = contentHeight / (double) mHeightUnits;

        int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        int width = MeasureSpec.getSize(widthMeasureSpec);

        boolean canAutoDetermine = true;
        if (widthMode == MeasureSpec.EXACTLY) {
            this.mWidthUnits = (int) (width / mUnitSize);
            canAutoDetermine = false;
        }

        unMeasureChildren.clear();
        int maxX = 0;
        for (int i = 0, N = getChildCount(); i < N; i++) {
            View child = getChildAt(i);
            LayoutParams layoutParams = (LayoutParams) child.getLayoutParams();

            if (layoutParams.width == LayoutParams.MATCH_PARENT && this.mWidthUnits <= 0 && canAutoDetermine) {
                //最大高度还没有计算出来，所以先不计算child的高度
                unMeasureChildren.add(child);
                continue;
            }

            measureChild(child);
            if (child.getVisibility() != GONE) {
                maxX = Math.max(layoutParams.x + layoutParams.widthUnits, maxX);
            }
        }

        if (canAutoDetermine) {
            if (mAutoDetermineWidth) {
                this.mWidthUnits = maxX;
            }
            width = (int) (this.mWidthUnits * mUnitSize + getPaddingLeft() + getPaddingRight());
        }

        //计算child 为match_parent的高度
        for (int i = 0, N = unMeasureChildren.size(); i < N; i++) {
            measureChild(unMeasureChildren.get(i));
        }
        unMeasureChildren.clear();

        setMeasuredDimension(width, height);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

        if (mDependOn == 0) {
            measureDependOnWidth(widthMeasureSpec, heightMeasureSpec);
        } else {
            measureDependOnHeight(widthMeasureSpec, heightMeasureSpec);
        }
    }

    private int getSpec(int parentUnits, int marginUnits, int childLp, int childUnits) {
        int size;
        int mode;
        if (childLp == LayoutParams.MATCH_PARENT) {
            size = unitToSize(parentUnits - marginUnits);
            mode = MeasureSpec.EXACTLY;
        } else if (childLp == LayoutParams.WRAP_CONTENT) {
            mode = MeasureSpec.UNSPECIFIED;
            size = unitToSize(parentUnits);

        } else if (childLp == 0) {
            size = unitToSize(childUnits);
            mode = MeasureSpec.EXACTLY;
        } else {
            size = childLp;
            mode = MeasureSpec.EXACTLY;
        }
        return MeasureSpec.makeMeasureSpec(size, mode);
    }

    private void measureChild(View child) {

        LayoutParams lp = (LayoutParams) child.getLayoutParams();

        //处理TextView文字适配
        if (child instanceof TextView && lp.textSize > 0) {

            int textSize = unitToSize(lp.textSize);
            TextView textView = (TextView) child;
            textView.setTextSize(TypedValue.COMPLEX_UNIT_PX, textSize);
        }

        if (child instanceof ImageView){
            if (lp.supper_image_max_height!=-1){
                ((ImageView) child).setMaxHeight(unitToSize(lp.supper_image_max_height));
            }
            if (lp.supper_image_max_width!=-1){
                ((ImageView) child).setMaxWidth(unitToSize(lp.supper_image_max_width));
            }
        }

        try {
            if (lp.supper_min_width!=-1){
                child.setMinimumWidth(unitToSize(lp.supper_min_width));
            }
            if (lp.supper_min_height!=-1){
                child.setMinimumWidth(unitToSize(lp.supper_min_height));
            }
            child.measure(
                    getSpec(mWidthUnits, lp.leftMargin + lp.rightMargin,
                            lp.width, lp.widthUnits),
                    getSpec(mHeightUnits, lp.topMargin + lp.bottomMargin,
                            lp.height, lp.heightUnits)
            );
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public int unitToSize(int units) {
        int pixels = (int) (units * mUnitSize);
        if (pixels == 0 && units > 0) {
            pixels = 1;
        }
        return pixels;
    }

    private int sizeToUnit(int size) {
        return (int) (Math.ceil(size / getUnitSize()));
    }

    @SuppressLint("RtlHardcoded")
    private void layoutChild(View child) {

        LayoutParams lp = (LayoutParams) child.getLayoutParams();
        if (lp.isLayoutFinish) {
            return;
        }
        int extraX = 0;
        int extraY = 0;
        int x = lp.x;
        int y = lp.y;

        if (lp.baseTo != 0 || lp.baseYTo != 0 || lp.baseXTo != 0) {
            View baseXView = null, baseYView = null, baseView = null;
            for (int i = 0; i < getChildCount(); i++) {
                View temp = getChildAt(i);
                if (temp == child) {
                    continue;
                }

                if (temp.getId() == lp.baseTo) {
                    baseView = temp;
                }

                if (temp.getId() == lp.baseXTo) {
                    baseXView = temp;
                }
                if (temp.getId() == lp.baseYTo) {
                    baseYView = temp;
                }
            }

            if (baseXView == null) {
                baseXView = baseView;
            }

            if (baseYView == null) {
                baseYView = baseView;
            }
            if (baseXView != null) {
                layoutChild(baseXView);
                extraX = getExtraForBaseType(lp.xBaseType, baseXView.getLeft(),
                        baseXView.getMeasuredWidth(), child.getMeasuredWidth());
            }

            if (baseYView != null) {
                layoutChild(baseYView);
                extraY = getExtraForBaseType(lp.yBaseType, baseYView.getTop(),
                        baseYView.getMeasuredHeight(), child.getMeasuredHeight());
            }
        }

        int gravity = lp.layout_gravity;
        int parentWith = getMeasuredWidth();
        int parentHeight = getMeasuredHeight();
        int width = child.getMeasuredWidth();
        int height = child.getMeasuredHeight();
        if (extraX == 0) {
            switch (gravity & Gravity.HORIZONTAL_GRAVITY_MASK) {
                case Gravity.CENTER_HORIZONTAL:
                    extraX = (parentWith - width) / 2;
                    break;
                case Gravity.RIGHT:
                    extraX = parentWith - width;

            }

        }
        if (extraY == 0) {
            switch (gravity & Gravity.VERTICAL_GRAVITY_MASK) {

                case Gravity.CENTER_VERTICAL:
                    extraY = (parentHeight - height) / 2;
                    break;
                case Gravity.BOTTOM:
                    extraY = parentHeight - height;
                    break;
            }
        }

        int l = getPaddingLeft() + unitToSize(x) + lp.leftMargin + extraX;
        int t = getPaddingTop() + unitToSize(y) + lp.topMargin + extraY;
        child.layout(
                l,
                t,
                l + child.getMeasuredWidth(),
                t + child.getMeasuredHeight()
        );
        lp.isLayoutFinish = true;
    }

    private int getExtraForBaseType(BaseType baseType, int start, int len, int contentSize) {
        int extra;
        switch (baseType) {
            case START: {
                extra = start;
                break;
            }

            case END: {
                extra = start + len;
                break;
            }

            case CENTER: {
                extra = start + len / 2;
                break;
            }
            case CENTER_ALIGN: {
                extra = start + len / 2 - contentSize / 2;
                break;
            }
            default:
                extra = 0;
        }
        return extra;
    }

    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
        int N = getChildCount();
        for (int i = 0; i < N; i++) {
            LayoutParams lp = (LayoutParams) getChildAt(i).getLayoutParams();
            lp.isLayoutFinish = false;
        }
        for (int i = 0; i < N; i++) {
            View child = getChildAt(i);
            layoutChild(child);

        }
    }

    Paint p = new Paint();

    @Override
    public void draw(Canvas canvas) {
        super.draw(canvas);
        if (mOnDrawListener != null) {
            mOnDrawListener.onDrawOver(canvas);
        }
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        if (mOnDrawListener != null) {
            mOnDrawListener.onDraw(canvas);
        }

        if (isInEditMode()&&editMode) {
            int textSize = getWidth() / 15;
            p.setColor(Color.parseColor("#30ff0000"));
            p.setTextSize(textSize);
            canvas.drawText(toString(), 0, textSize, p);
        }

    }

    @Override
    public String toString() {
        return getTag() + "{"
                + getWidth() + "*" + getHeight()
                + ", " + mWidthUnits + "*" + mHeightUnits + "\n"
                + ", " + mUnitSize +
                '}';
    }

    @Override
    protected ViewGroup.LayoutParams generateDefaultLayoutParams() {
        return new LayoutParams();
    }

    @Override
    protected ViewGroup.LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) {
        return new LayoutParams(p);
    }

    @Override
    public ViewGroup.LayoutParams generateLayoutParams(AttributeSet attrs) {
        return new LayoutParams(getContext(), attrs);
    }

    public SupperLayout setDependOnWidth(boolean width) {
        this.mDependOn = width ? 0 : 1;
        return this;
    }

    public int getWidthUnits() {
        return mWidthUnits;
    }

    public int getHeightUnits() {
        return mHeightUnits;
    }

    public double getUnitSize() {
        return mUnitSize;
    }

    public SupperLayout setLayoutHeightUnits(int heightUnits) {
        this.mHeightUnits = heightUnits;
        return this;
    }

    public SupperLayout setLayoutWidthUnits(int widthUnits) {
        this.mWidthUnits = widthUnits;
        return this;
    }

    public SupperLayout setOnDrawListener(OnDrawListener mOnDrawListener) {
        this.mOnDrawListener = mOnDrawListener;
        return this;
    }

    public void layoutChildUnit(View child, int x, int y, int w, int h) {
        LayoutParams lp = (LayoutParams) child.getLayoutParams();
        lp.position(x, y);
        lp.units(w, h);
        child.layout(unitToSize(x), unitToSize(y), unitToSize(w), unitToSize(h));
    }

    public void layoutChild(View child, int l, int t, int r, int b) {
        LayoutParams lp = (LayoutParams) child.getLayoutParams();
        lp.x = sizeToUnit(l);
        lp.y = sizeToUnit(t);
        lp.widthUnits = sizeToUnit(r - l);
        lp.heightUnits = sizeToUnit(b - t);

        child.layout(l, t, r, b);
    }

    public void setWidthUnits(int units) {
        this.mWidthUnits = units;
        mAutoDetermineWidth = (mWidthUnits == AUTO);
    }

    public void setHeightUnits(int units) {
        this.mHeightUnits = units;
        mAutoDetermineHeight = (mHeightUnits == AUTO);
    }

    public int getChildCountInX(int x) {
        int childCount = getChildCount();
        int count = 0;
        for (int i = 0; i < childCount - 1; i++) {
            LayoutParams lp = (LayoutParams) getChildAt(i).getLayoutParams();
            if (lp.x == x) {
                count++;
            }
        }
        return count;
    }

    public int getChildCountInY(int y) {
        int childCount = getChildCount();
        int count = 0;
        for (int i = 0; i < childCount; i++) {
            LayoutParams lp = (LayoutParams) getChildAt(i).getLayoutParams();
            if (lp.y == y) {
                count++;
            }
        }
        return count;
    }

    @SuppressWarnings("WeakerAccess")
    public static class LayoutParams extends MarginLayoutParams {

        int x;
        int y;
        int heightUnits;
        int widthUnits;
        int textSize;
        int baseTo;
        int baseXTo;
        int baseYTo;
        BaseType xBaseType;
        BaseType yBaseType;
        int layout_gravity;
        int supper_min_width;
        int supper_image_max_width;
        int supper_min_height;
        int supper_image_max_height;
        private boolean isLayoutFinish;

        public LayoutParams(Context c, AttributeSet attrs) {
            super(c, attrs);
            TypedArray a = c.obtainStyledAttributes(attrs, R.styleable.SupperLayout_Layout);

            y = a.getInt(R.styleable.SupperLayout_Layout_y, 0);
            heightUnits = a.getInt(R.styleable.SupperLayout_Layout_heightUnits, 0);
            x = a.getInt(R.styleable.SupperLayout_Layout_x, 0);
            widthUnits = a.getInt(R.styleable.SupperLayout_Layout_widthUnits, 0);
            textSize = a.getInt(R.styleable.SupperLayout_Layout_textSizeUnits, -1);
            supper_min_width = a.getInt(R.styleable.SupperLayout_Layout_supper_min_width, -1);
            supper_image_max_width = a.getInt(R.styleable.SupperLayout_Layout_supper_image_max_width, -1);
            supper_min_height = a.getInt(R.styleable.SupperLayout_Layout_supper_min_height, -1);
            supper_image_max_height = a.getInt(R.styleable.SupperLayout_Layout_supper_image_max_height, -1);
            baseTo = a.getResourceId(R.styleable.SupperLayout_Layout_baseTo, 0);
            baseXTo = a.getResourceId(R.styleable.SupperLayout_Layout_baseXTo, 0);
            baseYTo = a.getResourceId(R.styleable.SupperLayout_Layout_baseYTo, 0);
            xBaseType = getBaseType(a, R.styleable.SupperLayout_Layout_xBaseType);
            yBaseType = getBaseType(a, R.styleable.SupperLayout_Layout_yBaseType);
            layout_gravity = a.getInt(R.styleable.SupperLayout_Layout_android_layout_gravity, Gravity.NO_GRAVITY);
            a.recycle();
        }

        private BaseType getBaseType(TypedArray a, int styleable) {
            int value = a.getInt(styleable, BaseType.START.ordinal());
            return BaseType.values()[value];
        }

        public LayoutParams() {
            this(WRAP_CONTENT, WRAP_CONTENT);
        }

        public LayoutParams(int width, int height) {
            super(width, height);
            position(0, 0);
            units(1, 1);
        }

        public LayoutParams(MarginLayoutParams source) {
            super(source);
        }

        public LayoutParams(ViewGroup.LayoutParams source) {
            super(source);
        }

        public void position(int x, int y) {
            this.x = x;
            this.y = y;
        }

        public void units(int widthUnits, int heightUnits) {
            this.widthUnits = widthUnits;
            this.heightUnits = heightUnits;
        }

        public LayoutParams setTextSize(int textSize) {
            this.textSize = textSize;
            return this;
        }

        public int getX() {
            return x;
        }

        public int getY() {
            return y;
        }

        @Override
        protected void setBaseAttributes(TypedArray a, int widthAttr, int heightAttr) {

            if (a.hasValue(heightAttr)) {
                height = a.getLayoutDimension(heightAttr, "layout_height");
            } else {
                this.height = WRAP_CONTENT;
            }
            if (a.hasValue(widthAttr)) {
                width = a.getLayoutDimension(widthAttr, "layout_width");
            } else {
                this.width = WRAP_CONTENT;
            }
        }
    }

    public interface OnDrawListener {
        void onDraw(Canvas c);

        void onDrawOver(Canvas c);
    }
}
